package com.biodiv.miracle.web.servlet;

import com.alibaba.fastjson2.JSON;
import com.biodiv.miracle.support.utils.AnnotationUtils;
import com.biodiv.miracle.support.utils.ResourceUtils;
import com.biodiv.miracle.web.adapter.DefaultHandlerAdapter;
import com.biodiv.miracle.web.adapter.RequestMappingHandlerAdapter;
import com.biodiv.miracle.web.support.annotation.ResponseBody;
import com.biodiv.miracle.web.adapter.HandlerAdapter;
import com.biodiv.miracle.web.handler.*;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * @Author: tianquan
 * @CreateTime: 2025-05-25  18:50
 * @Description: 中央控制器
 */
public class DispatcherServlet extends FrameworkServlet {

    private final Logger logger = Logger.getLogger(DispatcherServlet.class.getName());
    private final List<HandlerMapping> handlerMappings;
    private final List<HandlerAdapter> handlerAdapters;

    public DispatcherServlet() {
        this.handlerMappings = new ArrayList<>(8);
        handlerMappings.add(new RequestMappingHandlerMapping());
        this.handlerAdapters = new ArrayList<>(8);
        handlerAdapters.add(new RequestMappingHandlerAdapter());
        handlerAdapters.add(new DefaultHandlerAdapter());
    }

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) {
        request.setAttribute("dispatcherServlet", this);
        request.setAttribute("applicationContext", applicationContext);
        doDispatch(request, response);
    }

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
        HandlerExecutionChain handlerExecutionChain = null;
        try {
            // 获取请求执行链
            handlerExecutionChain = this.getHandler(request);

            // 获取能处理当前请求的适配器
            HandlerAdapter handlerAdapter = getHandlerAdapter(handlerExecutionChain.getHandler());

            // 执行前置拦截器
            if (!handlerExecutionChain.applyPreHandle(request, response)) {
                return;
            }

            // 执行处理器
            Object result = handlerAdapter.handle(request, response, handlerExecutionChain.getHandler());

            // 执行后置拦截器
            handlerExecutionChain.applyPostHandle(request, response, result);

            // 将处理结果刷新给客户端
            flushResult(result, response, handlerExecutionChain.getHandler());

            // 执行清理资源的后置拦截器
            handlerExecutionChain.triggerAfterCompletion(request, response, null);

        } catch (Exception e) {
            try {
                if (handlerExecutionChain != null) {
                    handlerExecutionChain.triggerAfterCompletion(request, response, e);
                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        }
    }

    private void flushResult(Object result, HttpServletResponse response, Object handler) {
         if (result == null) {
            return;
        }
        try {
            boolean isResponseBodyAnnotation = isResponseBodyAnnotation(handler);
            if (isResponseBodyAnnotation) {
                // 输出json格式数据
                String resultString;
                if (result instanceof String str) {
                    resultString = str;
                } else {
                    resultString = JSON.toJSONString(result);
                }
                response.setContentType("application/json");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write(resultString);
            } else {
                // todo 输出html格式数据
                if (result instanceof String str) {
                    response.setContentType("text/html;charset=UTF-8");
                    // 找到静态资源
                    String resourcePath = "resource/webapp/" + str + ".html";
                    InputStream resource = applicationContext.getResource(resourcePath);
                    if (resource == null) {
                        throw new RuntimeException("not find" + "resource/webapp/" + result.toString() + ".html");
                    }
                    String html = ResourceUtils.convert(resource);
                    // 输出html格式数据
                    response.getWriter().write(html);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean isResponseBodyAnnotation(Object handler) {
        try {
            // 类上是否有ResponseBody注解
            boolean isResponseBody = AnnotationUtils.hasClassMetaAnnotation(handler.getClass(), ResponseBody.class);
            if (handler instanceof HandlerMethod handlerMethod) {
                isResponseBody = AnnotationUtils.hasClassMetaAnnotation(handlerMethod.getBean().getClass(), ResponseBody.class);
            }
            if (isResponseBody) {
                return true;
            }
            // 方法上是否有ResponseBody注解
            Method method = null;
            if (handler instanceof HandlerMethod handlerMethod) {
                method = handlerMethod.getMethod();
            } else if (handler instanceof Servlet servlet) {
                method = servlet.getClass().getMethod("service", ServletRequest.class, ServletResponse.class);
            }
            if (method != null) {
                ResponseBody annotation = method.getAnnotation(ResponseBody.class);
                return annotation != null;
            }
            return false;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    protected HandlerExecutionChain getHandler(HttpServletRequest request) {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            for (HandlerAdapter adapter : this.handlerAdapters) {
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }
        throw new ServletException("没有找到能解析" + handler + " 的适配器");
    }

}
